import git
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from datetime import datetime
import os
import pandas as pd
from matplotlib import font_manager
import calendar
from matplotlib.ticker import MaxNLocator

# 配置中文字体支持
try:
    font_path = "C:/Windows/Fonts/simhei.ttf"  # Windows字体路径
    font_prop = font_manager.FontProperties(fname=font_path)
    plt.rcParams['font.family'] = font_prop.get_name()
except:
    plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']  # 备选字体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

# 设置项目信息
repo_name = "he3pg"
repo_link = "https://gitee.com/he3db/he3pg"
clone_path = "he3pg"
visuals_dir = "visuals_he3pg"  # 修改为 visuals_he3pg

# 如果不存在则创建可视化目录
os.makedirs(visuals_dir, exist_ok=True)


def clone_or_update_repo():
    """克隆或更新仓库"""
    if os.path.exists(clone_path):
        print(f"更新现有仓库：{clone_path}")
        repo = git.Repo(clone_path)
        origin = repo.remote(name='origin')
        origin.pull()
    else:
        print(f"克隆仓库：{repo_link}")
        repo = git.Repo.clone_from(repo_link, clone_path)
    return repo


def analyze_commits(repo):
    """分析提交数据并返回结构化结果"""
    commits = list(repo.iter_commits('master'))

    # 初始化数据结构
    commit_data = []
    contributors = {}
    monthly_counts = {}
    weekday_counts = [0] * 7
    lines_changed = []
    files_changed = []

    for commit in commits:
        author = commit.author.name if commit.author else "Unknown"
        date = commit.committed_datetime
        month_key = date.strftime('%Y-%m')

        # 贡献者统计
        if author not in contributors:
            contributors[author] = {'commits': 0, 'lines_added': 0, 'lines_deleted': 0}
        contributors[author]['commits'] += 1

        # 月度统计
        monthly_counts[month_key] = monthly_counts.get(month_key, 0) + 1

        # 星期统计
        weekday_counts[date.weekday()] += 1

        # 差异统计
        lines_added, lines_deleted, files_changed_count = 0, 0, 0
        if commit.parents:
            parent = commit.parents[0]
            diffs = repo.git.diff(parent.hexsha, commit.hexsha, numstat=True).split('\n')
            for diff in diffs:
                if diff.strip():
                    parts = diff.split('\t')
                    if len(parts) >= 3:
                        try:
                            added = int(parts[0]) if parts[0] != '-' else 0
                            deleted = int(parts[1]) if parts[1] != '-' else 0
                            lines_added += added
                            lines_deleted += deleted
                            files_changed_count += 1
                        except ValueError:
                            pass

        lines_changed.append(lines_added + lines_deleted)
        files_changed.append(files_changed_count)

        commit_data.append({
            'author': author,
            'date': date,
            'hash': commit.hexsha,
            'lines_added': lines_added,
            'lines_deleted': lines_deleted,
            'files_changed': files_changed_count,
            'total_lines': lines_added + lines_deleted
        })

    return {
        'commit_data': pd.DataFrame(commit_data),
        'contributors': sorted(contributors.items(), key=lambda x: x[1]['commits'], reverse=True),
        'monthly_counts': monthly_counts,
        'weekday_counts': weekday_counts,
        'lines_changed': lines_changed,
        'files_changed': files_changed
    }


def generate_top_contributors_chart(contributors, repo_name):
    """生成前10名贡献者条形图"""
    top_10 = contributors[:10]
    names = [x[0] for x in top_10]
    counts = [x[1]['commits'] for x in top_10]

    plt.figure(figsize=(12, 6))
    ax = sns.barplot(x=counts, y=names, hue=names, orient='h', palette="viridis", legend=False)
    plt.title(f"{repo_name} - Top 10 Contributors", fontsize=14)
    plt.xlabel("Commit Count", fontsize=12)
    plt.ylabel("Contributor", fontsize=12)

    # 添加值标签
    for i, v in enumerate(counts):
        ax.text(v + 0.5, i, str(v), color='black', va='center')

    plt.tight_layout()
    plt.savefig(f"{visuals_dir}/{repo_name}_top_contributors.png", dpi=300, bbox_inches='tight')
    plt.close()


def generate_monthly_commits_chart(monthly_counts, repo_name):
    """生成月度提交折线图"""
    sorted_months = sorted(monthly_counts.items())
    months = [datetime.strptime(m[0], '%Y-%m').strftime('%b %Y') for m in sorted_months[-12:]]
    counts = [m[1] for m in sorted_months[-12:]]

    plt.figure(figsize=(14, 6))
    ax = sns.lineplot(x=months, y=counts, marker='o', linewidth=2.5)
    plt.title(f"{repo_name} - Monthly Commit Activity (Last 12 Months)", fontsize=14)
    plt.xlabel("Month", fontsize=12)
    plt.ylabel("Commit Count", fontsize=12)
    plt.xticks(rotation=45)
    plt.grid(True, linestyle='--', alpha=0.6)

    # 添加值标签
    for x, y in zip(months, counts):
        ax.text(x, y + 0.5, str(y), ha='center', va='bottom')

    plt.tight_layout()
    plt.savefig(f"{visuals_dir}/{repo_name}_monthly_commits.png", dpi=300, bbox_inches='tight')
    plt.close()


def generate_weekly_commits_chart(weekday_counts, repo_name):
    """生成每周提交分布条形图"""
    weekday_names = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']

    plt.figure(figsize=(10, 6))
    ax = sns.barplot(x=weekday_names, y=weekday_counts, hue=weekday_names, palette="coolwarm", legend=False)
    plt.title(f"{repo_name} - Weekly Commit Distribution", fontsize=14)
    plt.xlabel("Day of Week", fontsize=12)
    plt.ylabel("Commit Count", fontsize=12)
    plt.xticks(rotation=45)

    # 添加值标签
    for i, v in enumerate(weekday_counts):
        ax.text(i, v + 0.5, str(v), ha='center')

    plt.tight_layout()
    plt.savefig(f"{visuals_dir}/{repo_name}_weekly_commits.png", dpi=300, bbox_inches='tight')
    plt.close()


def generate_cumulative_commits_chart(commit_data, repo_name):
    """生成累计提交折线图"""
    commit_data = commit_data.sort_values('date')
    commit_data['cumulative'] = range(1, len(commit_data) + 1)

    plt.figure(figsize=(14, 6))
    sns.lineplot(x=commit_data['date'], y=commit_data['cumulative'], linewidth=2.5)
    plt.title(f"{repo_name} - Cumulative Commit Growth", fontsize=14)
    plt.xlabel("Date", fontsize=12)
    plt.ylabel("Cumulative Commits", fontsize=12)
    plt.xticks(rotation=45)
    plt.grid(True, linestyle='--', alpha=0.6)
    plt.tight_layout()
    plt.savefig(f"{visuals_dir}/{repo_name}_cumulative_commits.png", dpi=300, bbox_inches='tight')
    plt.close()


def generate_lines_changed_chart(lines_changed, repo_name):
    """生成每次提交变更行数箱线图"""
    plt.figure(figsize=(10, 6))

    # 计算四分位数范围并过滤异常值
    q1, q3 = np.percentile(lines_changed, [25, 75])
    iqr = q3 - q1
    lower_bound = q1 - 1.5 * iqr
    upper_bound = q3 + 1.5 * iqr
    filtered_data = [x for x in lines_changed if lower_bound <= x <= upper_bound]

    sns.boxplot(y=filtered_data, color=sns.color_palette("viridis")[0])
    plt.title(f"{repo_name} - Lines Changed Per Commit", fontsize=14)
    plt.ylabel("Lines Changed", fontsize=12)

    # 添加统计注释
    stats = {
        'Median': np.median(lines_changed),
        'Mean': np.mean(lines_changed),
        'Max': np.max(lines_changed),
        'Min': np.min(lines_changed)
    }
    plt.text(0.7, 0.9, '\n'.join([f"{k}: {v:.1f}" for k, v in stats.items()]),
             transform=plt.gca().transAxes, bbox=dict(facecolor='white', alpha=0.8))

    plt.tight_layout()
    plt.savefig(f"{visuals_dir}/{repo_name}_lines_changed.png", dpi=300, bbox_inches='tight')
    plt.close()


def generate_files_changed_chart(files_changed, repo_name):
    """生成每次提交变更文件数箱线图"""
    plt.figure(figsize=(10, 6))

    # 计算四分位数范围并过滤异常值
    q1, q3 = np.percentile(files_changed, [25, 75])
    iqr = q3 - q1
    lower_bound = q1 - 1.5 * iqr
    upper_bound = q3 + 1.5 * iqr
    filtered_data = [x for x in files_changed if lower_bound <= x <= upper_bound]

    sns.boxplot(y=filtered_data, color=sns.color_palette("magma")[0])
    plt.title(f"{repo_name} - Files Changed Per Commit", fontsize=14)
    plt.ylabel("Files Changed", fontsize=12)

    # 添加统计注释
    stats = {
        'Median': np.median(files_changed),
        'Mean': np.mean(files_changed),
        'Max': np.max(files_changed),
        'Min': np.min(files_changed)
    }
    plt.text(0.7, 0.9, '\n'.join([f"{k}: {v:.1f}" for k, v in stats.items()]),
             transform=plt.gca().transAxes, bbox=dict(facecolor='white', alpha=0.8))

    plt.tight_layout()
    plt.savefig(f"{visuals_dir}/{repo_name}_files_changed.png", dpi=300, bbox_inches='tight')
    plt.close()


def generate_report(repo_name, repo_link, analysis_results):
    """生成综合Markdown报告"""
    commit_data = analysis_results['commit_data']
    contributors = analysis_results['contributors']
    monthly_counts = analysis_results['monthly_counts']
    weekday_counts = analysis_results['weekday_counts']
    lines_changed = analysis_results['lines_changed']
    files_changed = analysis_results['files_changed']

    report = f"""# {repo_name} 仓库分析报告

## 仓库信息
- **仓库URL：** [{repo_link}]({repo_link})
- **分析日期：** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
- **总提交数：** {len(commit_data)}
- **总贡献者数：** {len(contributors)}
- **首次提交：** {commit_data['date'].min().strftime('%Y-%m-%d')}
- **最后一次提交：** {commit_data['date'].max().strftime('%Y-%m-%d')}

## 仓库选择理由
我们选择He3PG仓库进行分析是因为：

1. 它是一个高性能的分布式PostgreSQL数据库，具有显著的技术复杂性，使其成为开发模式分析的有趣对象。
2. 该项目展示了活跃的开发，拥有超过250次提交和多个贡献者，为分析提供了大量数据。
3. 作为一个数据库项目，它代表了基础设施软件的重要类别，与应用软件的开发模式不同。
4. 该仓库显示了健康的协作模式，既有核心维护者的贡献，也有社区贡献者的贡献。

## 前10名贡献者
![Top Contributors]({visuals_dir}/{repo_name}_top_contributors.png)

## 月度提交活动（过去12个月）
![Monthly Commits]({visuals_dir}/{repo_name}_monthly_commits.png)

## 每周提交分布
![Weekly Commits]({visuals_dir}/{repo_name}_weekly_commits.png)

## 累计提交增长
![Cumulative Commits]({visuals_dir}/{repo_name}_cumulative_commits.png)

## 每次提交变更行数
![Lines Changed]({visuals_dir}/{repo_name}_lines_changed.png)

## 每次提交变更文件数
![Files Changed]({visuals_dir}/{repo_name}_files_changed.png)

## 统计摘要
### 变更行数统计
- **中位数：** {np.median(lines_changed):.1f}
- **平均值：** {np.mean(lines_changed):.1f}
- **标准差：** {np.std(lines_changed):.1f}
- **最小值：** {np.min(lines_changed)}
- **最大值：** {np.max(lines_changed)}

### 变更文件数统计
- **中位数：** {np.median(files_changed):.1f}
- **平均值：** {np.mean(files_changed):.1f}
- **标准差：** {np.std(files_changed):.1f}
- **最小值：** {np.min(files_changed)}
- **最大值：** {np.max(files_changed)}

### 最活跃的一天
最活跃的一天是：{['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'][np.argmax(weekday_counts)]}

## 详细贡献者数据
| 排名 | 贡献者 | 提交数 |
|------|---------|--------|
"""

    for i, (contributor, stats) in enumerate(contributors[:10], 1):
        report += f"| {i} | {contributor} | {stats['commits']} |\n"

    report_filename = f"report-{repo_name}.md"
    with open(report_filename, 'w', encoding='utf-8') as f:
        f.write(report)

    print(f"报告生成：{report_filename}")


def main():
    print(f"分析仓库：{repo_name}")

    # 克隆/更新仓库
    repo = clone_or_update_repo()

    # 分析提交数据
    analysis_results = analyze_commits(repo)

    # 生成可视化图表
    generate_top_contributors_chart(analysis_results['contributors'], repo_name)
    generate_monthly_commits_chart(analysis_results['monthly_counts'], repo_name)
    generate_weekly_commits_chart(analysis_results['weekday_counts'], repo_name)
    generate_cumulative_commits_chart(analysis_results['commit_data'], repo_name)
    generate_lines_changed_chart(analysis_results['lines_changed'], repo_name)
    generate_files_changed_chart(analysis_results['files_changed'], repo_name)

    # 生成报告
    generate_report(repo_name, repo_link, analysis_results)

    print("分析成功完成！")


if __name__ == "__main__":
    main()